/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.android.newsreader; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.os.Build; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.view.View; import android.view.View.OnClickListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.SpinnerAdapter; /** * Main activity: shows headlines list and articles, if layout permits. * * This is the main activity of the application. It can have several different layouts depending * on the SDK version, screen size and orientation. The configurations are divided in two large * groups: single-pane layouts and dual-pane layouts. * * In single-pane mode, this activity shows a list of headlines using a {@link HeadlinesFragment}. * When the user clicks on a headline, a separate activity (a {@link ArticleActivity}) is launched * to show the news article. * * In dual-pane mode, this activity shows a {@HeadlinesFragment} on the left side and an * {@ArticleFragment} on the right side. When the user selects a headline on the left, the * corresponding article is shown on the right. * * If an Action Bar is available (large enough screen and SDK version 11 or up), navigation * controls are shown in the Action Bar (whether to show tabs or a list depends on the layout). * If an Action Bar is not available, a regular image and button are shown in the top area of * the screen, emulating an Action Bar. */ public class NewsReaderActivity extends FragmentActivity implements HeadlinesFragment.OnHeadlineSelectedListener, CompatActionBarNavListener, OnClickListener { // Whether or not we are in dual-pane mode boolean mIsDualPane = false; // The fragment where the headlines are displayed HeadlinesFragment mHeadlinesFragment; // The fragment where the article is displayed (null if absent) ArticleFragment mArticleFragment; // The news category and article index currently being displayed int mCatIndex = 0; int mArtIndex = 0; NewsCategory mCurrentCat; // List of category titles final String CATEGORIES[] = { "Top Stories", "Politics", "Economy", "Technology" }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_layout); // find our fragments mHeadlinesFragment = (HeadlinesFragment) getSupportFragmentManager().findFragmentById( R.id.headlines); mArticleFragment = (ArticleFragment) getSupportFragmentManager().findFragmentById( R.id.article); // Determine whether we are in single-pane or dual-pane mode by testing the visibility // of the article view. View articleView = findViewById(R.id.article); mIsDualPane = articleView != null && articleView.getVisibility() == View.VISIBLE; // Register ourselves as the listener for the headlines fragment events. mHeadlinesFragment.setOnHeadlineSelectedListener(this); // Set up the Action Bar (or not, if one is not available) int catIndex = savedInstanceState == null ? 0 : savedInstanceState.getInt("catIndex", 0); setUpActionBar(mIsDualPane, catIndex); // Set up headlines fragment mHeadlinesFragment.setSelectable(mIsDualPane); restoreSelection(savedInstanceState); // Set up the category button (shown if an Action Bar is not available) Button catButton = (Button) findViewById(R.id.categorybutton); if (catButton != null) { catButton.setOnClickListener(this); } } /** Restore category/article selection from saved state. */ void restoreSelection(Bundle savedInstanceState) { if (savedInstanceState != null) { setNewsCategory(savedInstanceState.getInt("catIndex", 0)); if (mIsDualPane) { int artIndex = savedInstanceState.getInt("artIndex", 0); mHeadlinesFragment.setSelection(artIndex); onHeadlineSelected(artIndex); } } } @Override public void onRestoreInstanceState(Bundle savedInstanceState) { restoreSelection(savedInstanceState); } /** Sets up Action Bar (if present). * * @param showTabs whether to show tabs (if false, will show list). * @param selTab the selected tab or list item. */ public void setUpActionBar(boolean showTabs, int selTab) { if (Build.VERSION.SDK_INT < 11) { // No action bar for you! // But do not despair. In this case the layout includes a bar across the // top that looks and feels like an action bar, but is made up of regular views. return; } android.app.ActionBar actionBar = getActionBar(); actionBar.setDisplayShowTitleEnabled(false); // Set up a CompatActionBarNavHandler to deliver us the Action Bar nagivation events CompatActionBarNavHandler handler = new CompatActionBarNavHandler(this); if (showTabs) { actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_TABS); int i; for (i = 0; i < CATEGORIES.length; i++) { actionBar.addTab(actionBar.newTab().setText(CATEGORIES[i]).setTabListener(handler)); } actionBar.setSelectedNavigationItem(selTab); } else { actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_LIST); SpinnerAdapter adap = new ArrayAdapter<String>(this, R.layout.actionbar_list_item, CATEGORIES); actionBar.setListNavigationCallbacks(adap, handler); } // Show logo instead of icon+title. actionBar.setDisplayUseLogoEnabled(true); } @Override public void onStart() { super.onStart(); setNewsCategory(0); } /** Sets the displayed news category. * * This causes the headlines fragment to be repopulated with the appropriate headlines. */ void setNewsCategory(int categoryIndex) { mCatIndex = categoryIndex; mCurrentCat = NewsSource.getInstance().getCategory(categoryIndex); mHeadlinesFragment.loadCategory(categoryIndex); // If we are displaying the article on the right, we have to update that too if (mIsDualPane) { mArticleFragment.displayArticle(mCurrentCat.getArticle(0)); } // If we are displaying a "category" button (on the ActionBar-less UI), we have to update // its text to reflect the current category. Button catButton = (Button) findViewById(R.id.categorybutton); if (catButton != null) { catButton.setText(CATEGORIES[mCatIndex]); } } /** Called when a headline is selected. * * This is called by the HeadlinesFragment (via its listener interface) to notify us that a * headline was selected in the Action Bar. The way we react depends on whether we are in * single or dual-pane mode. In single-pane mode, we launch a new activity to display the * selected article; in dual-pane mode we simply display it on the article fragment. * * @param index the index of the selected headline. */ @Override public void onHeadlineSelected(int index) { mArtIndex = index; if (mIsDualPane) { // display it on the article fragment mArticleFragment.displayArticle(mCurrentCat.getArticle(index)); } else { // use separate activity Intent i = new Intent(this, ArticleActivity.class); i.putExtra("catIndex", mCatIndex); i.putExtra("artIndex", index); startActivity(i); } } /** Called when a news category is selected. * * This is called by our CompatActionBarNavHandler in response to the user selecting a * news category in the Action Bar. We react by loading and displaying the headlines for * that category. * * @param catIndex the index of the selected news category. */ @Override public void onCategorySelected(int catIndex) { setNewsCategory(catIndex); } /** Save instance state. Saves current category/article index. */ @Override protected void onSaveInstanceState(Bundle outState) { outState.putInt("catIndex", mCatIndex); outState.putInt("artIndex", mArtIndex); super.onSaveInstanceState(outState); } /** Called when news category button is clicked. * * This is the button that we display on UIs that don't have an action bar. This button * calls up a list of news categories and switches to the given category. */ @Override public void onClick(View v) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Select a Category"); builder.setItems(CATEGORIES, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { setNewsCategory(which); } }); AlertDialog d = builder.create(); d.show(); } }